package com.fuxia.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.beanutils.BeanUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlParser {

	/**
	 * 根据路径获取Document对象
	 * @param xmlFilePath
	 * @return
	 * @throws Exception
	 */
	private static Document getDocuemnt(String xmlFilePath) throws Exception{
		DocumentBuilderFactory docFac = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = docFac.newDocumentBuilder();
		URI uri = Thread.currentThread().getContextClassLoader().getResource(xmlFilePath).toURI();
		InputStream fis = new FileInputStream(new File(uri));
		Document doc = builder.parse(fis);
		fis.close();
		return doc;
	}
	
	/**
	 * 解析xml文件
	 * @param filePath
	 * 			xml文件路径
	 * @param fileds
	 * 			实体字段与xml文件中的节点名称的映射
	 * @param entity
	 * 			实体Class
	 * @return
	 */
	public static List<Object> parseDocuemnt(String filePath,Map<String,String> fileds,Class<?> entity) {
		List<Object> result = new ArrayList<Object>();
		try {
			Document doc = getDocuemnt(filePath);
			Element root = doc.getDocumentElement();
			NodeList dataSources = root.getChildNodes();
			if (dataSources != null) {
				for (int i = 0; i < dataSources.getLength(); i++) {
					Node dataSource = dataSources.item(i);
					if (dataSource.getNodeType() == Node.ELEMENT_NODE) {
						NodeList dataSourceInfo = dataSource.getChildNodes();
						Object obj = entity.newInstance() ;
						if (dataSourceInfo != null && dataSourceInfo.getLength() > 0) {
							for (int j = 0; j < dataSourceInfo.getLength(); j++) {
								Node cur = dataSourceInfo.item(j);
								
								if (cur.getNodeType() == Node.ELEMENT_NODE) {
									
									String curNodeValue = cur.getFirstChild()
											.getNodeValue();
									BeanUtils.setProperty(obj, fileds.get(
											cur.getNodeName()).toString(),
											curNodeValue);
									
								}
							}
						}
						result.add(obj);
					}
				}
			}
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return null ;
		}
	}
	
	
	/**
	 * 向xml中写入项
	 * @param xmlPath
	 * @param values
	 * @return
	 */
	public static boolean writeXmlEntry(String xmlPath,Map<String,Map<String,String>> values) {

		try {
			Document doc = getDocuemnt(xmlPath);
			Element root = doc.getDocumentElement();
			
			for(Iterator<Map.Entry<String, Map<String,String>>> iter=values.entrySet().iterator();iter.hasNext();) {
				
				Map.Entry<String, Map<String,String>> cur = iter.next() ;
				
				Node rootNode = doc.createElement(cur.getKey()) ;
				
				Map<String,String> value = cur.getValue() ;
				for(Iterator<Map.Entry<String, String>> curIter = value.entrySet().iterator();curIter.hasNext();) {
					Map.Entry<String, String> entry = curIter.next() ;
					Node curEle = doc.createElement(entry.getKey()) ;
					curEle.appendChild(doc.createTextNode(entry.getValue())) ;
					rootNode.appendChild(curEle) ;
				}
				root.appendChild(rootNode) ;
				
			}
			
			output(doc,xmlPath);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false ;
		}
	}
	
	/**
	 * 将更改写入文件
	 * @param doc
	 * @param path
	 * @throws Exception
	 */
	private static void  output(Document doc,String path) throws Exception {
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		DOMSource source = new DOMSource(doc) ;
		URI uri = Thread.currentThread().getContextClassLoader().getResource(path).toURI();
		File file = new File(uri) ;
		StreamResult result = new StreamResult(file);
		System.out.println(uri.getPath());
		transformer.transform(source, result);
	}
	
	public static void main(String[] args) {
		
		//------------------select----------------------
		Map<String,String> fileds = new HashMap<String, String>();
		fileds.put("name", "name") ;
		fileds.put("author", "author");
		fileds.put("pubdate", "publishDate");
		
		List<Object> result =parseDocuemnt("xml/books.xml", fileds, Book.class) ;
		for(Object book:result) {
			System.out.println(book);
		}
		
		// -------------------write--------------------
		
		Map<String,String> aBook = new HashMap<String, String>();
		aBook.put("name", "Hello,C++") ;
		aBook.put("author", "Fuxia");
		aBook.put("pubdate", "2012-02-25") ;
		
		Map<String,Map<String,String>> aBookNode = new HashMap<String, Map<String,String>>();
		aBookNode.put("book", aBook) ;
		
		writeXmlEntry("xml/books.xml", aBookNode) ;
	} 
}
